/*
 * sgip.c
 *
 *  Created on: 2012-2-23
 *      Author: skyrain
 *
 */
#include "cmdmsg.h"
#include "skynet.h"
#include <pthread.h>

#define MAXLINE 4096
static int seq = 0;
static pthread_mutex_t seq_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_key_t connst;
static pthread_once_t = PTHREAD_ONCE_INIT;

void* func(void*);
void dateget(const int);
int gethead(int, msg_head*);
void bindhandle(const int, msg_head*);
void unbindhandel(int, msg_head*);
int deliverhandel(int connfd, int bodylen, msg_head* head);

static void const_once(void)
{
	pthread_key_create(connst, const_destructor);
}

static void const_destructor(void *ptr)
{
	free(ptr);
}

int main(int argc, char **argv)
{

	int listenfd, connfd;
	pthread_t tid;
	socklen_t cliaddlen;
	struct sockaddr_in *cliaddr;

	listenfd = tcp_port_listen(8801, NULL);

	while (1)
	{
		connfd = accept(listenfd, cliaddr, &cliaddlen);
		pthread_create(&tid, NULL, &func, (void *) connfd);
	}

}

void* func(void *attr)
{
	int constvalue = 0;
	const_once();
	if (pthread_getspecific(connst) == NULL)
	{
		pthread_setspecific(connst, &constvalue);
	}
	pthread_detach(pthread_self());
	dateget((int) attr);
	close((int) attr);
	return (NULL);
}

void dateget(const int connfd)
{
	size_t n;
	msg_head *head;
	int exitst = 0;
	/*添加30秒超时自动断开连接
	 *
	 */

	while ((n = gethead(connfd, head)) == 20)
	{
		switch (head->command_id)
		{
		case SGIP_BIND:
			bindhandle(connfd, head);
			break;
		case SGIP_UNBIND:
			unbindhandel(connfd, head);
			exitst = 1;
			break;
		case SGIP_DELIVER:
			if (deliverhandel(connfd, head->msg_len, head) == -1)
			{
				exitst = 1;
			}
			break;
		default:
			break;
		}
		if (exitst == 1)
		{
			break;
		}
	}
	return;
}

int gethead(int connfd, msg_head* head)
{
	int n = -1;
	if ((n = recv(connfd, head, 20, 0)) != 20)
	{
		return n;
	}
	head->command_id = ntohl(head->command_id);
	head->msg_len = ntohl(head->msg_len);
	head->node_id = ntohl(head->node_id);
	head->time = ntohl(head->time);
	head->seq = ntohl(head->seq);

	return n;
}

//bind处理函数
void bindhandle(const int connfd, msg_head* head)
{
	msg_bind *body = NULL;
	msg_head *rehead = NULL;
	msg_bind_resp *rebody = NULL;
	struct iovec msg_iov[2];
	int* bconnst;

	if ((bconnst = pthread_getspecific(connst)) == NULL)
	{
		*bconnst = 0;
		pthread_setspecific(connst, &bconnst);
	}

	if ((body = calloc(0, LEN_BIND)) == NULL)
	{
		err_sys("recv bind body mem create error");
		return;
	}
	if ((rehead = calloc(0, 20)) == NULL)
	{
		err_sys("recv bind rehead mem create error");
		return;
	}
	if ((rebody = calloc(0, LEN_BIND_RESP)) == NULL)
	{
		err_sys("recv bind rebody mem create error");
		return;
	}

	if (recv(connfd, body, LEN_BIND, 0) == LEN_BIND)
	{

		fillrehead(rehead, head,LEN_BIND_RESP+20,SGIP_BIND_RESP);
		msg_iov[0].iov_base = rehead;
		msg_iov[0].iov_len = 20;
		msg_iov[1].iov_base = rebody;
		msg_iov[1].iov_len = LEN_BIND_RESP;
		if (*bconnst == 1)
		{
			rebody->result = 2;
			Sendmsg_tcp(connfd, msg_iov, 2, 0);
		}
		else if (((msg_bind*) body)->login_type != 2)
		{
			rebody->result = 4;
			Sendmsg_tcp(connfd, msg_iov, 2, 0);
		}
		else
		{
			if (!strcmp(((msg_bind*) body)->login_name, "abc") && !strcmp(((msg_bind*) body)->login_password, "def"))
			{
				rebody->result = 0;
				bconnst = (int*) pthread_getspecific(connst);
				*bconnst = 1;
			}
			else
			{
				rebody->result = 1;
			}
			Sendmsg_tcp(connfd, msg_iov, 2, 0);
		}
	}
	else
	{
		err_sys("recv bind body msg error");
	}
	free(body);
	free(rehead);
	free(rebody);
	return;
}

//处理unbind命令
void unbindhandel(int connfd, msg_head* head)
{
	msg_head* rehead;
	if ((rehead = calloc(0, 20)) == NULL)
	{
		err_sys("recv unbind rehead mem create error");
		close(connfd);
		return;
	}
	fillrehead(rehead,head,20,SGIP_UNBIND_RESP);
	send(connfd, rehead, 20);
	free(rehead);
	close(connfd);
	return;
}

//处理deliver命令
int deliverhandel(int connfd, int bodylen, msg_head* head)
{
	msg_deliver *body = NULL;
	void* tempbody = NULL;
	char* msg_content = NULL;
	int result = 0;
	msg_head* rehead = NULL;
	msg_deliver_resp rebody = NULL;

	int* bconnst = NULL;
	bconnst = pthread_getspecific(connst);
	if (bconnst == NULL || (*bconnst) == 0)
	{
		return -1;
	}

	if ((tempbody = calloc(0, bodylen - 20)) == NULL)
	{
		err_sys("deliverhandel recv msgbody error");
		return -1;
	}
	rehead = calloc(0, 20);
	if (recv(connfd, tempbody, bodylen - 20, 0) == (bodylen - 20))
	{
		filldeliver(rebody, tempbody, msg_content, bodylen, LEN_DELIVER - 8, bodylen - 8);
	}

	//业务处理

	fillrehead(rehead,head,LEN_DELIVER_RESP+20,SGIP_DELIVER_RESP);
	Sendmsg_tcp(connfd, , 2, 0);



	return result;

}

//填充deliver消息体
void filldeliver(msg_deliver* msg, const void* bodybuf, char* contbuf, int bodylen, int contentpos, int revpos)
{
	memccpy(msg, bodybuf, LEN_DELIVER - 8);
	msg->message_length = ntohl(msg->message_length);
	memccpy(contbuf, bodybuf + LEN_DELIVER - 8, ((msg_deliver *) bodybuf)->message_length);
	memccpy(msg + revpos, bodybuf + LEN_DELIVER - 8 + msg->message_length, 8);
	msg->message_length = ntohl(msg->message_length);
}

//填充信息头函数
msg_head* fillhead(msg_head* head, int command_id, int msg_len)
{
	head->command_id = htonl(command_id);
	head->msg_len = htonl(msg_len + 20);
	head->node_id = htonl(3024012345);
	head->time = htonl(time2int());
	seqhandel(head);
	head->seq = htonl(head->seq);
	return head;
}

//填充返回消息头
int fillrehead(msg_head* rehead, const msg_head* head, int msg_len, int command_id)
{
	int result = 0;
	rehead->msg_len = htonl(msg_len + 20);
	rehead->command_id = htonl(rehead->command_id);
	rehead->node_id = htonl(head->node_id);
	rehead->time = htonl(head->time);
	rehead->seq = htonl(head->seq);
	return result;
}

void seqhandel(msg_head* head)
{
	pthread_mutex_lock(seq_lock);
	head->seq = seq++;
	pthread_mutex_unlock(seq_lock);
}
